<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-tabs</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
    <style>
        [v-cloak] {
            visibility: hidden;
        }
        .tabs {
            font-size: 14px;
            color: #657180;
        }
        .tabs-bar:after {
            content: '';
            display: block;
            width: 100%;
            height: 1px;
            background: #d7dde4;
            margin-top: -1px;
        }
        .tabs-tab {
            display: inline-block;
            padding: 4px 16px;
            margin-right: 6px;
            background: #fff;
            border: 1px solid #d7dde4;
            cursor: pointer;
            position: relative;
        }
        .tabs-tab-active {
            color: #3399ff;
            border-top: 1px solid #3399ff;
            border-bottom: 1px solid #fff;
        }
        .tabs-tab-active:before {
            content: '';
            display: block;
            height: 1px;
            background: #3399ff;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
        }
        .tabs-content {
            padding: 8px 0;
        }
        .hidden {
            display: none;
        }
    </style>
</head>
<body>
<div id="app" v-cloak>
    <tabs v-model="activeKey">
        <pane label="标签一" name="1" :closable="true">
            标签一的内容
        </pane>
        <pane label="标签二" name="2">
            标签二的内容
        </pane>
        <pane label="标签三" name="3" :closable="true">
            标签三的内容
        </pane>
    </tabs>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
    Vue.component('tabs', {
        template: `
            <div class="tabs">
                <div class="tabs-bar">
                    <div :class="tabCls(item)" v-for="(item, index) in navList">
                         <button v-if="item.closable" @click="handleClose(index)"
                            type="button" class="close" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                        <span @click="handleChange(index)">{{ item.label }}</span>
                    </div>
                </div>
                <div class="tabs-content">
                    <slot></slot>
                </div>
            </div>
        `,
        props: {
            value: {
                type: [String, Number]
            }
        },
        data() {
            return {
                currentValue: this.value,
                navList: []
            }
        },
        methods: {
            getTabs() {
                return this.$children.filter(item => item.$options.name === 'pane');
            },
            updateNav() {
                this.navList = [];
                this.getTabs().forEach((pane, index) => {
                    this.navList.push({
                        label: pane.label,
                        name: pane.name || index,
                        closable: pane.closable
                    });
                    if (!pane.name) pane.name = index;
                    if (index === 0) {
                        if (!this.currentValue) {
                            this.currentValue = pane.name || index;
                        }
                    }
                });
                this.updateStatus();
            },
            updateStatus() {
                let tabs = this.getTabs();
                tabs.forEach(tab => tab.show = (tab.name === this.currentValue));
            },
            tabCls(item) {
                return [
                    'tabs-tab',
                    {
                        'tabs-tab-active': item.name === this.currentValue
                    }
                ]
            },
            handleChange(index) {
                let nav = this.navList[index];
                let name = nav.name;
                this.currentValue = name;
                this.$emit('input', name);
                this.$emit('on-click', name);
            },
            handleClose(index) {
                this.handleChange( (index+1) % this.navList.length );
                this.updateStatus();
                    this.$children.splice(index, 1);
                this.updateNav();
            },
        },
        watch: {
            value(val) {
                this.currentValue = val;
            },
            currentValue() {
                this.updateStatus();
            }
        }
    });
    Vue.component('pane', {
        name: 'pane',
        template: `
            <div class="pane" v-show="show">
                <slot></slot>
            </div>
        `,
        props: {
            name: {
                type: String
            },
            label: {
                type: String,
                default: ''
            },
            closable: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                show: true
            }
        },
        methods: {
            updateNav() {
                this.$parent.updateNav();
            }
        },
        watch: {
            label() {
                this.updateNav();
            }
        },
        mounted() {
            this.updateNav();
        },
        beforeDestroy() {
        }
    });
    let app = new Vue({
        el: '#app',
        data: {
            activeKey: '1'
        }
    })
</script>
</body>
</html>